﻿using System.Linq;
using System.Web.Mvc;
using BlankMvc.Dao;
using BlankMvc.Dao.Entities.Impl;
using BlankMvc.Dao.Repository.Base;
using BlankMvc.Services.Interfaces;
using Castle.Core;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using FluentNHibernate.Cfg;
using NHibernate;
using NHibernate.Caches.SysCache;

namespace BlankMvc {
	public class DependencyInstaller : IWindsorInstaller {

		public void Install(IWindsorContainer container, IConfigurationStore store) {
			container.Kernel.ComponentRegistered += Kernel_ComponentRegistered;
			//Register all components
			container.Register(
				//All controllers
				Classes.FromThisAssembly().BasedOn<IController>().LifestyleTransient(),
				//Nhibernate session factory
				Component.For<ISessionFactory>().UsingFactoryMethod(CreateSessionFactory).LifeStyle.Singleton,
				//Unitofwork interceptor
				Component.For<UnitOfWorkInterceptor>().LifeStyle.Transient,
				//All services
				Classes.FromAssemblyContaining<IService>().BasedOn<IService>().WithService.FromInterface(),
				//All repoistories
				Classes.FromAssemblyContaining<IRepository>().BasedOn<IRepository>().WithService.FromInterface());
		}

		/// <summary>
		/// Creates NHibernate Session Factory.
		/// </summary>
		/// <returns>NHibernate Session Factory</returns>
		private static ISessionFactory CreateSessionFactory() {
			NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration().Configure();
			ISessionFactory rez = Fluently.Configure(cfg)
				.Mappings(x => x.FluentMappings.AddFromAssemblyOf<UserMap>())
				.Cache(c => c.UseQueryCache().UseSecondLevelCache().ProviderClass<SysCacheProvider>())
				.BuildSessionFactory();
			return rez;
			//new NHibernate.Tool.hbm2ddl.SchemaExport(cfg).SetOutputFile("C:\\MyDDL.sql").Execute(true, true, false);
		}

		void Kernel_ComponentRegistered(string key, Castle.MicroKernel.IHandler handler) {
			//Intercept all methods of all repositories.
			if (UnitOfWorkHelper.IsRepositoryClass(handler.ComponentModel.Implementation))
				handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(UnitOfWorkInterceptor)));
			//Intercept all methods of classes those have at least one method that has UnitOfWork attribute.
			if (handler.ComponentModel.Implementation.GetMethods().Any(UnitOfWorkHelper.HasUnitOfWorkAttribute))
				handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(UnitOfWorkInterceptor)));
		}
	}
}
